/** Naive NN-ZDD with IDF-Cut-off
 * 
 * 
 * @author Yong Boon, Lim (yongboon.lim@gmail.com)
 */

package core;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;

import measure.DocumentFreq;
import search.FileIndexBuilder;
import util.DocUtils;
import util.FileFinder;

public class NNZDDIdfApprox extends NNZDDBasic {

	// ZDD
	DocumentFreq _dF;
	double _pctThreshold;
	// Lucene
	
	public NNZDDIdfApprox(String trainDataDir, double pctThreshold) {
		super(trainDataDir);
		_pctThreshold = pctThreshold;
		_nnDescShort = "NN-ZDD-IDFAPPROX-LUC-" + Double.toString(_pctThreshold);
		_nnDescLong = "Nearest Neighbor with ZDD Inverse Document Freq (Using Lucene to retrieve doc)";
		
	}
	
	@Override
	public void init() {
		super.init();
		_dF = new DocumentFreq();
	}
	
	private void dFApprox(double pctThreshold) {
		ArrayList<File> files = FileFinder.GetAllFiles( _trainDataDir, "", true);

		for (File f : files) {
			String fileContent = DocUtils.ReadFile(f);
			Map<Object, Double> wordCount = DocUtils.ConvertToFeatureMapFilter(fileContent);
			
			for (Map.Entry<Object, Double> me : wordCount.entrySet()) {
				_dF.put((String)me.getKey());
			}
		}
		
		DocumentFreq dF = new DocumentFreq();
		int totalFile = files.size();
		
		for (Entry<String, Integer> e : _dF.documentFreqDict().entrySet()) {
			if ((double)e.getValue()/totalFile < pctThreshold) {
				dF.put(e.getKey(), e.getValue());
			}
		}
		_dF = dF;
	}

	// Convert topic to ZDD
	@Override
	public int topic2Zdd(File file) {
		String fileContent = DocUtils.ReadFile(file);
		Map<Object, Double> wordCount = DocUtils.ConvertToFeatureMapFilter(fileContent);
		int zddTopic = _zdd.base();

		for (Map.Entry<Object, Double> me : wordCount.entrySet()) {
			if (_dF.containsKey((String)me.getKey())) {
				// If the stem word have not been created as variable
				if (!_stemVarDict.containsKey(me.getKey())) {
					int zddVar = _zdd.createVar();
					_stemVarDict.put((String) me.getKey(), zddVar);
				}
				zddTopic = changeWith(zddTopic, _stemVarDict.get(me.getKey()));
			}
		}
		
		return zddTopic;
		
	}
	@Override
	public void build() {
		dFApprox(_pctThreshold);
		super.build();
	}
	
	@Override
	public double reduceScore(int zdd, Map<Object, Double> targetWordCount) {
		// Empty Set
		if (zdd == 0)
			return _zddEmptyCost;
		// Base Set
		if (zdd == 1)
			return _zddBaseCost;

		int zddLow = _zdd.subset0(zdd, _zdd.getVar(zdd));
		int zddHigh = _zdd.subset1(zdd, _zdd.getVar(zdd));
		
		// Calculate IDF
		String word = _stemVarInvDict.get(_zdd.getVar(zdd));
//		System.out.println(word + ", " + _dF.getIDF(word));
		double zddContain = (targetWordCount.containsKey(word)) ? _dF.getIDF(word) : 0;

		double zddHighCost = reduceScore(zddHigh, targetWordCount) + zddContain;
		double zddLowCost = reduceScore(zddLow, targetWordCount);

		double zddCost = 0;
		boolean maxBranch;

		if (zddHighCost > zddLowCost) {
			zddCost = zddHighCost;
			maxBranch = true;
		} else {
			zddCost = zddLowCost;
			maxBranch = false;
		}
		_nodeMaxBranchDict.put(zdd, maxBranch);

		return zddCost;
	}
	
	@Override
	public void clear() {
		super.clear();
		_dF = null;
	}
	

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
